﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.IO.Ports;
using System.Windows.Threading;

namespace serialPort_tool
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        bool save_log = false;
        string log_path = null;
        int read_overtime = 0;
        SerialPort ComPort = new SerialPort();//声明一个串口
        DispatcherTimer autoSendTick = new DispatcherTimer();//定时发送 

        public MainWindow()
        {
            InitializeComponent();
        }

        private void change_text_font_size(TextBox textBox, MouseWheelEventArgs e)
        {
            if ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control)/**检测是否按下ctrl键*/
                return;

            if (e.Delta > 0)
            {
                textBox.FontSize += 1;
                if (textBox.FontSize > 72)
                    textBox.FontSize = 72;
            }
            else
            {
                textBox.FontSize -= 1;
                if (textBox.FontSize < 8)
                    textBox.FontSize = 8;
            }
        }

        private string ascii_to_hex(string ascii)
        {
            string text = null;

            foreach (Byte data in ascii)
            {
                text += data.ToString("X2");
            }
            return add_space(text, 2);
        }

        private string hex_to_ascii(string hex)
        {
            string tmp;
            string text = hex;
            text = text.Replace(" ", "");  /**删除空格符*/

            byte[] b = new byte[text.Length / 2];
            for (int i = 0; i < text.Length / 2; i++)
            {
                tmp = text.Substring(i * 2, 2);
                b[i] = Convert.ToByte(tmp, 16);
            }
            return Convert.ToString(System.Text.Encoding.ASCII.GetString(b));
        }
        /**菜单栏按钮事件函数*/
        #region 
        private void set_button_Click(object sender, RoutedEventArgs e)
        {
            port_params sw = new port_params();
            sw.Show();
        }

        private void switch_button_Click(object sender, RoutedEventArgs e)
        {
            if (ComPort.IsOpen == false)
            {
                try
                {
                    int i = 0;
                    string output;

                    StreamReader sr = File.OpenText("..\\Config.txt");
                    while ((output = sr.ReadLine()) != null)
                    {
                        if (i == 0)
                            ComPort.PortName = output;
                        else if (i == 1)
                            ComPort.BaudRate = Convert.ToInt32(output);
                        else if (i == 2)
                        {
                            if (output == "None")
                                ComPort.Parity = (Parity)0;
                            else if (output == "Odd")
                                ComPort.Parity = (Parity)1;
                            else if (output == "Even")
                                ComPort.Parity = (Parity)2;
                            else if (output == "Mark")
                                ComPort.Parity = (Parity)3;
                            else if (output == "Space")
                                ComPort.Parity = (Parity)4;
                        }
                        else if (i == 3)
                            ComPort.DataBits = Convert.ToInt32(output);
                        else if (i == 4)
                            ComPort.StopBits = (StopBits)Convert.ToDouble(output);
                        i++;
                    }
                    sr.Close();

                    ComPort.ReadBufferSize = 1024;
                    ComPort.WriteBufferSize = 1024;
                    ComPort.DataReceived += new SerialDataReceivedEventHandler(ComReceive);//串口接收中断
                    autoSendTick.Tick += new EventHandler(autoSend);//定时发送中断
                    ComPort.Open();

                    port_info.Content = "Serial: [" + ComPort.PortName + ", " + ComPort.BaudRate + ", " + ComPort.DataBits + " ]";
                    switch_button.ToolTip = "关闭串口";

                    //Uri uri = new Uri("pause_64.png", UriKind.Relative);
                    //BitmapImage bimp = new BitmapImage(uri);
                    //switch_button.Background = new ImageBrush(bimp);
                }
                catch
                {
                    MessageBox.Show("无法打开串口,请检测此串口是否有效或被其他占用！");
                }
            }
            else 
            {
                try
                {
                    ComPort.Close();
                }
                catch
                {
                    MessageBox.Show("无法关闭串口，原因未知！");
                }
                port_info.Content = "Port: [Null]";
                autoSendTick.Stop();
                send_auto.IsChecked = false;
                switch_button.ToolTip = "打开串口";
                save_log = false;
            }
        }

        void save_log_file(string str)
        {
            if (save_log == true && log_path != null)
            {
                FileStream log = new FileStream(log_path, FileMode.Append);
                StreamWriter w_log = new StreamWriter(log);

                w_log.Write(str);
                w_log.Close();
                log.Close();
            }
        }

        private void save_button_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.SaveFileDialog log_file = new Microsoft.Win32.SaveFileDialog();
            log_file.DefaultExt = ".txt";
            log_file.FileName = "log-" + DateTime.Now.ToString("yyyyMMdd");
            log_file.Filter = "会话日志(.txt)|*.txt";
            log_file.RestoreDirectory = true;

            Nullable<bool> result = log_file.ShowDialog();

            if (result == true)
            {
                save_log = true;
                log_path = log_file.FileName.ToString();
                FileStream fs = (FileStream)log_file.OpenFile();
                fs.Close();
            }
        }

        private void reset_button_Click(object sender, RoutedEventArgs e)
        {
            send_bytes.Text = "0";
            recv_bytes.Text = "0";
        }

        private void about_button_Click(object sender, RoutedEventArgs e)
        {
            port_about sw = new port_about();
            sw.Show();
        }
        #endregion

        /**数据接收区事件函数*/
        #region
        private void ComReceive(object sender, SerialDataReceivedEventArgs e)//接收数据 数据在接收中断里面处理  
        {
            try
            {
                string recData;//接收数据转码后缓存 
                string recv_buf = null;
                StringBuilder recBuffer16 = new StringBuilder();//定义16进制接收缓存 

                System.Threading.Thread.Sleep(read_overtime);

                byte[] recBuffer = new byte[ComPort.BytesToRead];//接收数据缓存  
                ComPort.Read(recBuffer, 0, recBuffer.Length);//读取数据  
                recData = System.Text.Encoding.Default.GetString(recBuffer);//转码  

                

                this.recv_box.Dispatcher.Invoke(//WPF为单线程，此接收中断线程不能对WPF进行操作，用如下方法才可操作  
                new Action(
                        delegate
                        {
                           // recv_box.ScrollToEnd();

                            recv_bytes.Text = (Convert.ToInt32(recv_bytes.Text) + recBuffer.Length).ToString();//接收数据字节数  
 
                            if (recv_hex.IsChecked == true)
                            {
                                for (int i = 0; i < recBuffer.Length; i++)
                                {
                                    recBuffer16.AppendFormat("{0:X2}" + " ", recBuffer[i]);//X2表示十六进制格式（大写），域宽2位，不足的左边填0。  
                                } 
                            }

                            if (stop_recv.IsChecked == false && recData != null)
                            {
                                if (recv_ascii.IsChecked == true)
                                    recv_buf = "[" + System.DateTime.Now.ToString("HH:mm:ss") + " Recv]: " + recData + "\r\n\r\n";
                                else
                                    recv_buf = "[" + System.DateTime.Now.ToString("HH:mm:ss") + " Recv]: " + recBuffer16.ToString() + "\r\n\r\n";
                                recv_box.Text += recv_buf;//加显到接收区  
                                save_log_file(recv_buf);
                            }
                            recv_box.ScrollToEnd();
                        }
                    )
                );
           
            }
            finally
            {
                ;
            }
            
        }

        private void clear_recv_button_Click(object sender, RoutedEventArgs e)
        {
            recv_box.Clear();
        }

        private void recv_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            change_text_font_size(recv_box, e);
        }

        private void overtime_click(object sender, TextChangedEventArgs e)
        {
            read_overtime = Convert.ToInt32(overtime.Text);
        }
        #endregion

        /**数据发送区事件函数*/
        #region
        public string add_space(string str, int index)
        {
            StringBuilder sb = new StringBuilder(str);
            for (int i = index; i < sb.Length; i += index + 1)
            {
                sb.Insert(i, " ");
            }
            return sb.ToString();
        }

        private void send_box_TextChanged(object sender, TextChangedEventArgs e)
        {
            string text = send_box.Text;

            if (send_hex.IsChecked == true)
            {
                if (text.IndexOf(" ") >= 0)/**查找数据内容是否有空格符*/
                    text = text.Replace(" ", "");  /**删除空格符*/

                if (text.IndexOf("\r") >= 0)/**查找数据内容是否有换行符*/
                    text = text.Replace("\r", ""); /**删除换行符*/

                if (text.IndexOf("\n") >= 0)/**查找数据内容是否有换行符*/
                    text = text.Replace("\n", ""); /**删除换行符*/

                text = add_space(text, 2);
                send_box.Text = text;
                send_box.Select(send_box.Text.Length, 0);
            }
        }

        private void com_send()//发送数据 普通方法，发送数据过程中UI会失去响应  
        {
            string recv_buf = null;
            byte[] send_buf = null;//发送数据缓冲区  
            string send_data = send_box.Text;//复制发送数据，以免发送过程中数据被手动改变  

            if (ComPort.IsOpen == false)
            {
                MessageBox.Show("串口未打开！");
                return;
            }

            if (recv_echo.IsChecked == true && stop_recv.IsChecked == false)
            {
                try
                {
                    if ((recv_hex.IsChecked == true && send_hex.IsChecked == true) || (recv_hex.IsChecked == false && send_hex.IsChecked == false))
                        recv_buf = "[" + System.DateTime.Now.ToString("HH:mm:ss") + " Send]: " + send_data + "\r\n";
                    else if ((recv_hex.IsChecked == false && send_hex.IsChecked == true))
                        recv_buf = "[" + System.DateTime.Now.ToString("HH:mm:ss") + " Send]: " + hex_to_ascii(send_data) + "\r\n";
                    else if ((recv_hex.IsChecked == true && send_hex.IsChecked == false))
                        recv_buf = "[" + System.DateTime.Now.ToString("HH:mm:ss") + " Send]: " + ascii_to_hex(send_data) + "\r\n";
                }
                catch
                {
                    recv_buf = "[" + System.DateTime.Now.ToString("HH:mm:ss") + " Send]: " + send_data + "\r\n";
                }

                recv_box.Text += recv_buf;
                save_log_file(recv_buf);
                 recv_box.ScrollToEnd();
            }

            if (send_hex.IsChecked == true)//16进制发送  
            {
                try //尝试将发送的数据转为16进制Hex  
                {
                    send_data = send_data.Replace(" ", "");//去除16进制数据中所有空格  
                    send_data = send_data.Replace("\r", "");//去除16进制数据中所有换行  
                    send_data = send_data.Replace("\n", "");//去除16进制数据中所有换行 
 
                    if (send_data.Length == 1)//数据长度为1的时候，在数据前补0  
                    {
                        send_data = "0" + send_data;
                    }
                    else if (send_data.Length % 2 != 0)//数据长度为奇数位时，去除最后一位数据  
                    {
                        send_data = send_data.Remove(send_data.Length - 1, 1);
                    }

                    List<string> send_data16 = new List<string>();//将发送的数据，2个合为1个，然后放在该缓存里 如：123456→12,34,56  
                    for (int i = 0; i < send_data.Length; i += 2)
                    {
                        send_data16.Add(send_data.Substring(i, 2));
                    }
                    send_buf = new byte[send_data16.Count];//send_buf的长度设置为：发送的数据2合1后的字节数  
                    for (int i = 0; i < send_data16.Count; i++)
                    {
                        send_buf[i] = (byte)(Convert.ToInt32(send_data16[i], 16));//发送数据改为16进制  
                    }
                }
                catch //无法转为16进制时，出现异常  
                {
                    send_auto.IsChecked = false;//自动发送改为未选中  
                    autoSendTick.Stop();//关闭自动发送  
                    MessageBox.Show("请输入正确的16进制数据");
                    return;//输入的16进制数据错误，无法发送，提示后返回  
                }
            }
            else //ASCII码文本发送  
            {
                send_buf = System.Text.Encoding.Default.GetBytes(send_data);//转码 
            }

            try//尝试发送数据  
            {//如果发送字节数大于1000，则每1000字节发送一次  
                int sendTimes = (send_buf.Length / 1000);//发送次数  
                for (int i = 0; i < sendTimes; i++)//每次发生1000Bytes  
                {
                    ComPort.Write(send_buf, i * 1000, 1000);//发送send_buf中从第i * 1000字节开始的1000Bytes  
                    send_bytes.Text = (Convert.ToInt32(send_bytes.Text) + 1000).ToString();//刷新发送字节数
                    recv_box.Text += send_buf;
                }
                if (send_buf.Length % 1000 != 0)
                {
                    ComPort.Write(send_buf, sendTimes * 1000, send_buf.Length % 1000);//发送字节小于1000Bytes或上面发送剩余的数据  
                    send_bytes.Text = (Convert.ToInt32(send_bytes.Text) + send_buf.Length % 1000).ToString();//刷新发送字节数  
                }
            }
            catch//如果无法发送，产生异常  
            {
                if (ComPort.IsOpen == false)//如果ComPort.IsOpen == false，说明串口已丢失  
                {
                    //SetComLose();//串口丢失后相关设置  
                }
                else
                {
                    MessageBox.Show("无法发送数据，原因未知！");
                }
            }
        }

        bool send_hex_flag = true;
        private void send_hex_Click(object sender, RoutedEventArgs e)
        {
            send_ascii_flag = false;

            if (send_hex_flag == true)
                return;
             send_box.Text = ascii_to_hex(send_box.Text);
             send_hex_flag = true;

        }

        bool send_ascii_flag = false;
        private void send_ascii_Click(object sender, RoutedEventArgs e)
        {
            send_hex_flag = false;

            if (send_ascii_flag == true)
                return;
            send_box.Text = hex_to_ascii(send_box.Text);
            send_ascii_flag = true;
        }

        private void send_auto_Click(object sender, RoutedEventArgs e)
        {
            if (send_auto.IsChecked == true && ComPort.IsOpen == true)
            {
                autoSendTick.Interval = TimeSpan.FromMilliseconds(Convert.ToInt32(cycle_ms.Text));
                autoSendTick.Start();
            }
            else
            {
                autoSendTick.Stop();
            }
        }

        private void clear_send_button_Click(object sender, RoutedEventArgs e)
        {
            send_box.Clear();
        }

        void autoSend(object sender, EventArgs e)//自动发送  
        {
            com_send();//调用发送方法  
        } 

        private void send_data_button_Click(object sender, RoutedEventArgs e)
        {
            com_send();
        }
        
        private void send_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            change_text_font_size(send_box, e);
        }
        #endregion
    }
}
